package sketch.ounit.fuzz;

import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import randoop.ComponentManager;
import randoop.RConstructor;
import randoop.RMethod;
import sketch.util.Checker;

/**
 * This method is only used by Values.randomCreate(), or Values.randomMutate() methods
 * 
 * XXX be-aware of redundant, that may not be a case
 * */
public class SharedSequencePool {
	private static SequencePool pool = null;
	
	private static int count = 0;
	private static Map<Integer, AssembledSequenceObjectMutation<?>> current_mutation_sequence
	    = new LinkedHashMap<Integer, AssembledSequenceObjectMutation<?>>();
	private static Map<Integer, AssembledSequenceObjectCreation<?>> current_creation_sequence
	   = new LinkedHashMap<Integer, AssembledSequenceObjectCreation<?>>();
	private static Set<List<AssembledSequence<?>>> all_sequences = new LinkedHashSet<List<AssembledSequence<?>>>();
	
	//call this method before any round of test generation.
	public static void init_pool(int timelimit, Class<?>...classes) {
		pool = new SequencePool(timelimit, classes);
	}
	
	public static ComponentManager getComponents() {
		return pool.component_manager;
	}
	
	//call this method before starting a new round of test generation
	public static void startNewRound() {
		count = 0;
		current_mutation_sequence.clear();
		current_creation_sequence.clear();
	}
	
	//call this when creating a new mutation sequence 
	public static void addMutationSequence(AssembledSequenceObjectMutation<?> sequence) {
		current_mutation_sequence.put(count ++, sequence);
	}
	
	//call this when creating a new object creation sequence
	public static void addCreationSequence(AssembledSequenceObjectCreation<?> sequence) {
		current_creation_sequence.put(count++, sequence);
	}
	
	public static List<RConstructor> lookup_constructors(Class<?> clz) {
		return pool.lookup_constructors(clz);
	}
	
	public static List<RMethod> lookup_methods(Class<?> clz) {
		return pool.lookup_methods(clz);
	}
	
	//call this when finishing a test generation round, and getting all generated code
	public static List<String> getGeneratedCode() {
		//print out here
		List<String> code = new LinkedList<String>();
		for(int i = 0; i < count; i++) {
			if(current_mutation_sequence.containsKey(i)) {
				AssembledSequenceObjectMutation<?> sequence = current_mutation_sequence.get(i);
				code.add(sequence.toCodeString());
			} else if (current_creation_sequence.containsKey(i)) {
				AssembledSequenceObjectCreation<?> sequence = current_creation_sequence.get(i);
				code.add(sequence.toCodeString());
			} else {
				throw new RuntimeException("error in generating code, no sequence for i: " + i);
			}
		}
		return code;
	}
	
	public static boolean allValidSequence() {
//		private static Map<Integer, AssembledSequenceObjectMutation<?>> current_mutation_sequence
//	    = new LinkedHashMap<Integer, AssembledSequenceObjectMutation<?>>();
//	private static Map<Integer, AssembledSequenceObjectCreation<?>> current_creation_sequence
//	   = new LinkedHashMap<Integer, AssembledSequenceObjectCreation<?>>();
//		for(AssembledSequenceObjectMutation<?> seq : current_mutation_sequence.values()) {
//			if(seq.i)x
//		}
		for(AssembledSequenceObjectCreation<?> seq : current_creation_sequence.values()) {
			if(!seq.isValidSequence()) {
				return false;
			}
		}
		return true;
	}
	
	public static boolean isCurrentSequenceRedundant() {
		List<AssembledSequence<?>> current_list = getGeneratedSequence();
		if(all_sequences.contains(current_list)) {
			return true;
		}
		//add to the pool
		all_sequences.add(current_list);
		return false;
	}
	
	public static List<AssembledSequence<?>> getGeneratedSequence() {
		int size = current_mutation_sequence.size() + current_creation_sequence.size();
		List<AssembledSequence<?>> gen_sequences = new LinkedList<AssembledSequence<?>>();
		for(int i = 0; i < size; i++) {
			if(current_mutation_sequence.containsKey(i)) {
				gen_sequences.add(current_mutation_sequence.get(i));
			} else if(current_creation_sequence.containsKey(i)) {
				gen_sequences.add(current_creation_sequence.get(i));
			} else {
				Checker.fail("wrong, the sequence for index: " + i);
			}
		}
		return gen_sequences;
	}
	
	public static void output_randoop_tests() {
		pool.output_randoop_sequences();
	}
}